/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.common;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
 * The type ServiceUtils
 *
 * @author: Jack Lee
 */
@Slf4j
public class ServiceUtils {

    public static final String UTF8_BOM = "\uFEFF";

    public static String getProjectDeployJar() {
        return "lcm-project-deploy-tool.jar";
    }

    public static String getMetadataDeployJar() {
        return "metadata-deploy.jar";
    }

    public static String getManifestFileName() {
        return "manifest.json";
    }

    public static String getMetadataPackageExtension() {
        return ".mdpkg";
    }

    public static ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        mapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
        mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        mapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);//大小写脱敏 默认为false  需要改为tru
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        return mapper;
    }

    public static boolean isDeployTool() {
        boolean isProjectDeployTool = new File(FileServiceImp.combinePath(getStartupPath(), getProjectDeployJar())).exists();
        boolean isMetadataDeployTool = new File(FileServiceImp.combinePath(getStartupPath(), getMetadataDeployJar())).exists();
        return isProjectDeployTool || isMetadataDeployTool;
    }

    // 获取启动jar对应的路径
    public static String getStartupPath() {
        return CafEnvironment.getStartupPath();
    }

    /**
     * 获取安装盘的基路径 此方法有可能出错，当存在错误的server目录，或者jstack目录，使用时应检查文件是否存在
     */
    public static String getBasePath() {
        String basePath = isDeployTool() ? FileServiceImp.combinePath(CafEnvironment.getStartupPath(), "../../../../") : CafEnvironment.getBasePath();
        return basePath;
    }

    /**
     * 获取Server运行时路径，对应当前的jstack 此方法有可能出错，当存在错误的server目录，或者jstack目录，使用时应检查文件是否存在
     */
    public static String getServerRTPath() {
        return CafEnvironment.getServerRTPath();
    }

    public static String handlePath(String path) {
        return path.replace("\\", "/");
    }


    public static String getAbsoluteConfigFilePath(String fileName) {
        String absoluteConfigFilePath;
        if (!isDeployTool()) {
            absoluteConfigFilePath = FileServiceImp.combinePath(getServerRTPath(), fileName);
            if (!new File(absoluteConfigFilePath).exists()) {
                // 安装盘中找caf-bootstrap.jar文件的上层目录
                absoluteConfigFilePath = FileServiceImp.combinePath(new File(getStartupPath()).getParent(), fileName);
                if (!new File(absoluteConfigFilePath).exists()) {
                    throw new RuntimeException("无法获取配置文件路径：" + absoluteConfigFilePath);
                }
            }
        } else {
            String serverRuntimePathName = CafEnvironment.getServerRuntimePathName();
            absoluteConfigFilePath = FileServiceImp.combinePath(getBasePath(), serverRuntimePathName, fileName);
            if (!new File(absoluteConfigFilePath).exists()) {
                serverRuntimePathName = "jstack".equals(serverRuntimePathName) ? "server" : "jstack";
                absoluteConfigFilePath = FileServiceImp.combinePath(getBasePath(), serverRuntimePathName, fileName);
                if (!new File(absoluteConfigFilePath).exists()) {
                    throw new RuntimeException("无法获取配置文件路径：" + absoluteConfigFilePath);
                }
            }
        }
        return absoluteConfigFilePath;
    }

    public static Map<String, String> readCompressedFile(File file) {
        return readCompressedFile(file, null);
    }

    public static Map<String, String> readCompressedFile(File file, String fileName) {
        HashMap<String, String> fileContentMap = new HashMap<>();
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        ZipInputStream zis = null;
        ZipFile zipFile = null;
        try {
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            zis = new ZipInputStream(bis, StandardCharsets.UTF_8);
            ZipEntry zipEntry;
            zipFile = new ZipFile(file);
            while ((zipEntry = zis.getNextEntry()) != null) {
                if (!zipEntry.isDirectory()) {
                    // 读取单个文件
                    if (StringUtils.isEmpty(fileName)) {
                        // 读取全部文件
                        fileContentMap.putAll(readZipEntry(zipFile, zipEntry));
                    } else if (zipEntry.getName().equals(fileName)) {
                        return readZipEntry(zipFile, zipEntry);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("读取压缩包出错：" + file.getAbsolutePath(), e);
        } finally {
            try {
                if (zis != null) {
                    zis.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (fis != null) {
                    fis.close();
                }
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (IOException e) {
                log.warn("关闭压缩文件流失败：" + file.getAbsolutePath());
            }
        }
        return fileContentMap;
    }


    public static Map<String, String> readZipEntry(ZipFile zipFile, ZipEntry zipEntry) {
        HashMap<String, String> fileContentMap = new HashMap<>();
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            is = zipFile.getInputStream(zipEntry);
            isr = new InputStreamReader(is, StandardCharsets.UTF_8);
            br = new BufferedReader(isr);

            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            fileContentMap.put(zipEntry.getName(), removeUTF8BOM(sb.toString()));
        } catch (IOException e) {
            throw new RuntimeException("读取压缩包中文件失败：" + zipFile.getName() + "，" + zipEntry.getName(), e);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (isr != null) {
                    isr.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                log.warn("关闭压缩文件流失败：" + zipFile.getName() + "，" + zipEntry.getName());
            }
        }
        return fileContentMap;
    }

    public static void checkExist(File file, String msg) {
        if (!file.exists()) {
            throw new RuntimeException(msg);
        }
    }

    public static void checkEmpty(String str, String msg) {
        if (StringUtils.isEmpty(str)) {
            throw new RuntimeException(msg);
        }
    }

    public static void checkNPE(Object obj, String msg) {
        if (obj == null) {
            throw new RuntimeException(msg);
        }
    }

    private static String removeUTF8BOM(String s) {
        if (s.startsWith(UTF8_BOM)) {
            s = s.substring(1);
        }
        return s;
    }
}
